package org.dreamwork.fs;

import java.io.*;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * Created by IntelliJ IDEA.
 * User: seth.yang
 * Date: 2010-4-12
 * Time: 13:30:10
 */
public class FolderWalker {
    private String baseDir;
    private boolean createIndex = true;
    private Map<String, Long> map = new ConcurrentHashMap<String, Long> ();
    private PrintWriter writer;

    private List<IFileHandler> handlers = Collections.synchronizedList (new ArrayList<IFileHandler> ());

    private FileFilter dirFilter = new FileFilter() {
        public boolean accept (File pathname) {
            return pathname.isDirectory ();
        }
    };
    private WalkerFileFilter fileFilter = new WalkerFileFilter ();

    public FolderWalker (String baseDir) {
        this.baseDir = baseDir;
    }

    public boolean isCreateIndex () {
        return createIndex;
    }

    public void setCreateIndex (boolean createIndex) {
        this.createIndex = createIndex;
    }

    public void addFileHandler (IFileHandler handler) {
        handlers.add (handler);
    }

    public void removeFileHandler (IFileHandler handler) {
        handlers.remove (handler);
    }

    public List<IFileHandler> getFileHandlers () {
        List<IFileHandler> list = new ArrayList<IFileHandler> ();
        list.addAll (handlers);
        return list;
    }

    public String getBaseDir () {
        return baseDir;
    }

    public void setBaseDir (String baseDir) {
        this.baseDir = baseDir;
    }

    public String getFileFilter () {
        return fileFilter == null ? null : fileFilter.getFilter ();
    }

    public void setFileFilter (String fileFilter) {
        this.fileFilter.setFilter (fileFilter);
    }

    public void walk () throws IOException {
        File indexFile = new File (baseDir, ".index");
        if (createIndex) {
            if (indexFile.exists ()) {
                FileReader fr = null;
                try {
                    fr = new FileReader (indexFile);
                    BufferedReader reader = new BufferedReader (fr);
                    String line;
                    while ((line = reader.readLine ()) != null) {
                        String[] a = line.split ("\\|");
                        map.put (a[0], Long.parseLong (a[1]));
                    }
                } finally {
                    if (fr != null) fr.close ();
                }
            }
        }

        FileOutputStream fos = null;
        try {
            if (createIndex) {
                fos = new FileOutputStream (indexFile, true);
                writer = new PrintWriter (fos, true);
            }
            File file = new File (baseDir);
            listDir (file);
            if (createIndex) writer.flush ();
        } finally {
            if (fos != null) {
                fos.flush ();
                fos.close ();
            }
        }
    }

    private void processDirectory (File dir) {
        List<IFileHandler> list = getFileHandlers ();
        for (IFileHandler handler : list) {
            handler.processDir (dir);
        }
    }

    private void processFile (File file) {
        List<IFileHandler> list = getFileHandlers ();
        for (IFileHandler handler : list) {
            handler.processFile (file);
        }
    }

    private void listDir (File dir) {
        File[] dirs = dir.listFiles (dirFilter);
        processDirectory (dir);
        for (File di : dirs) listDir (di);
        File[] files = dir.listFiles (fileFilter);
        for (File file : files) recordFile (file);
    }

    private void recordFile (File file) {
        String key = file.getAbsolutePath ();
        if (map.containsKey (key)) {
            long last = map.get (key);
            if (last < file.lastModified ()) {
                processFile (file);
                map.put (key, file.lastModified ());
                if (createIndex) writer.printf ("%s|%d%n", key, file.lastModified ());
            }
        } else {
            processFile (file);
            map.put (key, file.lastModified ());
            if (createIndex) writer.printf ("%s|%d%n", key, file.lastModified ());
        }
    }

    public static void main (String[] args) throws Exception {
        FolderWalker walker = new FolderWalker ("D:\\IRXpert\\modules\\SMCenter\\web");
        walker.setFileFilter ("*.jasmine|*.jscx");
        walker.createIndex = false;
        walker.addFileHandler (new IFileHandler() {
            public void processFile (File file) {
                System.out.printf ("process file %s...%n", file.getAbsolutePath ());
            }

            public void processDir (File dir) {
                System.out.printf ("process dir %s...%n", dir.getAbsolutePath ());
            }
        });
        walker.walk ();
    }
}